package resolver.query


import org.apache.log4j.Logger
import org.codehaus.groovy.grails.commons.ApplicationHolder
import types.Hit

/**
 * User: wohlgemuth
 * Date: Feb 9, 2010
 * Time: 1:43:10 PM
 */
abstract class AbstractQuery implements Query,BatchedQuery{

  Logger logger = Logger.getLogger("query")

  //internal class needed for queries
  def queryClass = null

  //contains our batch queries
  Set<String> batchSet = new HashSet<String>()

  //controller

  public AbstractQuery() {
    queryClass = ApplicationHolder.application.getClassForName(getClassOfInterrest())
  }

  
  /**
   * executes a query against the queryClass table
   */
  def Set<Hit> executeQuery(String value) {
    try {

      def result = queryClass.executeQuery("Select distinct a.compound.id from ${getClassOfInterrest()} as a where LOWER(a.${getQuerySymbol()}) = ?", [value.toLowerCase()])

      Set<Hit> res = buildResult(result, value)

      return res
    }
    catch (Error e) {
      logger.error(e.getMessage(), e)
      throw new RuntimeException((e))
    }
  }

  /**
   * builds the result together
   */
  private Set<Hit> buildResult(result) {
    return buildResult(result, null)
  }
  /**
   * builds the result together
   */
  private Set<Hit> buildResult(result, value) {
    Set<Hit> res = new HashSet<Hit>()


    result.each {def syn ->
      Hit hit = new Hit()

      //in this case we have an array
      if (value == null) {
        hit.value = syn[1]
        hit.compoundId = syn[0]

      }
      else {
        hit.value = value
        hit.compoundId = syn

      }
      hit.type = Hit.COMPOUND_ID
      hit.origin = getOrigin()

      res.add(hit)
    }

    return res
  }

  /**
   * adds a query to the internal query stack
   */
  def void addQuery(String query) {
    batchSet.add(query.toLowerCase())
  }

  /**
   * executes the query
   */
  def Set<Hit> executeQuery() {
    logger.debug "execute batched query"

    if (batchSet.isEmpty()) {
      logger.debug "batch set was empty, so ne result possible"
      return new HashSet<Hit>()
    }
    try {

      StringBuffer query = new StringBuffer("Select distinct a.compound.id,a.name from ${getClassOfInterrest()} as a where lower(a.${getQuerySymbol()}) in (")

      boolean first = true

      //creates a big sub query
      batchSet.each {String s ->
        if (!first) {
          query.append(",")
        }
        first = false
        query.append('?')
      }

      query.append(")")

      logger.debug "query: ${query}"

      def result = queryClass.executeQuery(query.toString(), batchSet)

      batchSet.clear()

      return buildResult(result)

    }
    catch (Error e) {
      logger.error(e.getMessage(), e)
      throw new RuntimeException((e))
    }
  }

  /**
   * against which class do we query
   */
  protected abstract String getClassOfInterrest();

  /**
   * against which symbol do we query
   */
  protected abstract String getQuerySymbol();

  protected Class getOrigin(){
    return this.class
  }
}
